#pragma once

#include "my_disk_index.h"
#include "my_disk_data.h"
#include "my_disk_hotspot.h"
#include "my_disk_key_lock.h"
#include "event/my_event.h"
#include "event/my_aio_manager.h"
#include "comm/my_defs.h"

typedef struct my_disk_volume_s my_disk_volume_t;
typedef void(*my_disk_volume_err_cb)(my_disk_volume_t *volume);
typedef void(*my_disk_volume_open_done_cb)(my_disk_volume_t *volume, my_bool_t success);

struct my_disk_volume_s {
    // static configuration
    int                     level;          // for cache processor level
    const char              *disk_name;     // disk_name
    int                     fd;             // disk fd
    int                     id;             // volum id in disk cache
    int64_t                 start_offset;   // volume start offst in disk file
    int64_t                 volume_size;    // volume size in disk file
    int64_t                 item_num;       // index item num, volume_size / avg_file_size
    int64_t                 header_size;    // sizeof(my_disk_volume_header_t)
    int64_t                 index_size;     // index table size
    int64_t                 shm_size;       // shm file size
    int64_t                 index_offset;   // start_offset + header_size
    int64_t                 data_offset;    // index_offset + index_size
    int64_t                 data_size;      // (volume_size - header_size - index_size) aligned.

    my_disk_volume_err_cb   err_cb;         // called on disk failure.

    // context
    my_disk_volume_open_done_cb  done_cb;
    void                         *ctx;

    // dynamic
    char                    *name;          // volume name, disk_path + "_" + volume_id
    char                    *shm_name;      // shm file name, shm_prefix + volume name
    int                     shm_fd;         // shm file fd
    void                    *shm_addr;      // mmap addr
    char                    *tmp_buf;       // save volume header data
    my_aio_manager_t        *aio_manager;
    my_disk_hotspot_t       *hotspot;
    my_disk_key_lock_tab_t  lock_tab;
    my_disk_index_t         index;
    my_disk_data_t          disk_data;

    my_disk_vinfo_t         vinfo;
    my_aio_req_t            aio_req;        // for read/ write
    my_dispatch_event_t     dispatch_event;
};

static inline void
my_disk_volume_init(my_disk_volume_t *volume,
    int level, my_disk_volume_err_cb err_cb,
    my_disk_volume_open_done_cb done_cb, void *ctx) {

    bzero(volume, sizeof(my_disk_volume_t));
    volume->level = level;
    volume->err_cb = err_cb;
    volume->done_cb = done_cb;
    volume->ctx = ctx;
    volume->fd = INVALID_FD;
    volume->shm_fd = INVALID_FD;
    my_disk_key_lock_tab_init(&volume->lock_tab);
    my_disk_vinfo_init(&volume->vinfo);
    my_disk_index_init(&volume->index);
    my_disk_data_init(&volume->disk_data);
    my_dispatch_event_init(&volume->dispatch_event);
}

void
my_disk_volume_put(my_disk_volume_t *volume, my_cache_req_t *req);

void
my_disk_volume_reinsert(my_disk_volume_t *volume, my_cache_req_t *req,
    int64_t old_offset);

void
my_disk_volume_get(my_disk_volume_t *volume, my_cache_req_t *req);

void
my_disk_volume_open(my_disk_volume_t *volume, const char *disk_name,
    int volume_id, int fd, int64_t start_offset, int64_t volume_size, my_bool_t create_new);


void // TODO: to be realized
my_disk_volume_notify_close(my_disk_volume_t *volume, my_bool_t only_close_write) {
    my_disk_vinfo_close(&volume->vinfo, only_close_write);
    // TODO: start task for flush index table
    // TODO: start task for flush disk_buf
    // TODO: start task for flush volume_header
    // TODO: notify other tasks to quit
}

// void
// my_disk_volume_wait_exit(my_disk_volume_t *volume);